<?php
namespace app\common;


use app\common\model\ScoreLog as ModelScoreLog;
use think\facade\Db;
use think\Exception;

class ScoreLog
{
    /**
     * 添加积分
     * @param int $userId
     * @param int $credit
     * @param string $type
     * @param string $scene
     * @param string $remark
     * @param array $extra
     * @return bool
     * @throws Exception
     */
    public static function add($userId, $credit, $type, $scene, $remark = '', $extra = [])
    {
        if ($credit <= 0) {
            throw new Exception('积分值必须大于0');
        }

        return self::change($userId, $credit, $type, $scene, $remark, $extra);
    }

    /**
     * 扣除积分
     * @param int $userId
     * @param int $credit
     * @param string $type
     * @param string $scene
     * @param string $remark
     * @param array $extra
     * @return bool
     * @throws Exception
     */
    public static function reduce($userId, $credit, $type, $scene, $remark = '', $extra = [])
    {
        if ($credit <= 0) {
            throw new Exception('积分值必须大于0');
        }

        return self::change($userId, -$credit, $type, $scene, $remark, $extra);
    }

    /**
     * 通用积分变动方法
     * @param int $userId
     * @param int $credit
     * @param string $type
     * @param string $scene
     * @param string $remark
     * @param array $extra
     * @return bool
     * @throws Exception
     */
    private static function change($userId, $credit, $type, $scene, $remark, $extra)
    {
        try {
            Db::startTrans();

            // 1. 更新用户总积分
            $user = Db::name('user')
                ->where('id', $userId)
                ->lock(true)
                ->find();

            if (!$user) {
                throw new Exception('用户不存在');
            }

            $newCredit = $user['score'] + $credit;
            if ($newCredit < 0) {
                throw new Exception('积分不足');
            }

            Db::name('user')
                ->where('id', $userId)
                ->update(['score' => $newCredit]);

            // 2. 记录积分日志
            ModelScoreLog::addLog([
                'user_id' => $userId,
                'score' => $credit,
                'type' => $type,
                'scene' => $scene,
                'remark' => $remark,
                'extra' => $extra ? json_encode($extra, JSON_UNESCAPED_UNICODE) : null
            ]);

            Db::commit();
            return true;
        } catch (Exception $e) {
            Db::rollback();
            throw $e;
        }
    }

    /**
     * 获取用户当前积分
     * @param int $userId
     * @return int
     */
    public static function getScore($userId)
    {
        return Db::name('user')
            ->where('id', $userId)
            ->value('score') ?? 0;
    }
}